﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ArivisBuildService
{
    class ClientMessageEventArgs : EventArgs
    {
        public ClientMessageEventArgs(string message)
        {
            Message = message;
        }

        public string Message { get; private set; }
    }

    delegate void ClientMessageEventHandler(object sender, ClientMessageEventArgs args);

    class TcpService
    {
        private TcpListener tcpListener;
        private Thread listenThread;

        public TcpService()
        {
            this.tcpListener = new TcpListener(IPAddress.Loopback, 1724);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.IsBackground = true;
            this.listenThread.Start();
        }

        public event ClientMessageEventHandler ClientMessageRecieved;

        protected void OnClientMessageRecieved(object sender, ClientMessageEventArgs e)
        {
            try
            {
                if (this.ClientMessageRecieved != null)
                    this.ClientMessageRecieved(sender, e);
            }
            catch (Exception ex)
            {
                Console.WriteLine("{0}: {1}", System.DateTime.Now, ex.Message);
            }
        }

        private void ListenForClients()
        {
            this.tcpListener.Start();
            Console.WriteLine("{0}: Started: {1}", System.DateTime.Now, tcpListener.LocalEndpoint);

            while (true)
            {
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();

                //create a thread to handle communication 
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
                clientThread.Start(client);
            }
        }

        private void HandleClient(object client)
        {
            MemoryStream messagesStream = new MemoryStream();

            try
            {
                TcpClient tcpClient = (TcpClient)client;
                NetworkStream clientStream = tcpClient.GetStream();
                byte[] buffer = new byte[4096];
                int bytesRead;
                while (true)
                {
                    bytesRead = 0;

                    try
                    {
                        //blocks until a client sends a message
                        bytesRead = clientStream.Read(buffer, 0, 4096);
                        messagesStream.Write(buffer, 0, bytesRead);
                    }
                    catch
                    {
                        //a socket error has occured
                        break;
                    }

                    if (bytesRead == 0)
                    {
                        //the client has disconnected from the server
                        break;
                    }
                }
                tcpClient.Close();
            }
            catch { }

            var encoding = new UTF8Encoding();
            string message = Encoding.UTF8.GetString(messagesStream.ToArray());

            OnClientMessageRecieved(this, new ClientMessageEventArgs(message));
        }
    }
}
